home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / DistUpgrade / DistUpgradeViewGtk.py < prev    next >
Text File  |  2009-11-02  |  28KB  |  693 lines

  1. # DistUpgradeViewGtk.py 
  2. #  
  3. #  Copyright (c) 2004-2006 Canonical
  4. #  
  5. #  Author: Michael Vogt <michael.vogt@ubuntu.com>
  6. #  This program is free software; you can redistribute it and/or 
  7. #  modify it under the terms of the GNU General Public License as 
  8. #  published by the Free Software Foundation; either version 2 of the
  9. #  License, or (at your option) any later version.
  10. #  This program is distributed in the hope that it will be useful,
  11. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. #  GNU General Public License for more details.
  14. #  You should have received a copy of the GNU General Public License
  15. #  along with this program; if not, write to the Free Software
  16. #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  17. #  USA
  18.  
  19. import pygtk
  20. pygtk.require('2.0')
  21. import gtk
  22. import gtk.gdk
  23. import vte
  24. import gobject
  25. import pango
  26. import sys
  27. import locale
  28. import logging
  29. import time
  30. import subprocess
  31.  
  32. import apt
  33. import apt_pkg
  34. import os
  35.  
  36. from DistUpgradeApport import *
  37.  
  38. from DistUpgradeView import DistUpgradeView, FuzzyTimeToStr, InstallProgress, FetchProgress
  39. from SimpleGtkbuilderApp import SimpleGtkbuilderApp
  40.  
  41. import gettext
  42. from DistUpgradeGettext import gettext as _
  43.  
  44. def utf8(str):
  45.   return unicode(str, 'latin1').encode('utf-8')
  46.  
  47. class GtkCdromProgressAdapter(apt.progress.CdromProgress):
  48.     """ Report the cdrom add progress
  49.         Subclass this class to implement cdrom add progress reporting
  50.     """
  51.     def __init__(self, parent):
  52.         self.status = parent.label_status
  53.         self.progress = parent.progressbar_cache
  54.         self.parent = parent
  55.     def update(self, text, step):
  56.         """ update is called regularly so that the gui can be redrawn """
  57.         if text:
  58.           self.status.set_text(text)
  59.         self.progress.set_fraction(step/float(self.totalSteps))
  60.         while gtk.events_pending():
  61.           gtk.main_iteration()
  62.     def askCdromName(self):
  63.         return (False, "")
  64.     def changeCdrom(self):
  65.         return False
  66.  
  67. class GtkOpProgress(apt.progress.OpProgress):
  68.   def __init__(self, progressbar):
  69.       self.progressbar = progressbar
  70.       #self.progressbar.set_pulse_step(0.01)
  71.       #self.progressbar.pulse()
  72.  
  73.   def update(self, percent):
  74.       #if percent > 99:
  75.       #    self.progressbar.set_fraction(1)
  76.       #else:
  77.       #    self.progressbar.pulse()
  78.       self.progressbar.set_fraction(percent/100.0)
  79.       while gtk.events_pending():
  80.           gtk.main_iteration()
  81.  
  82.   def done(self):
  83.       self.progressbar.set_text(" ")
  84.  
  85.  
  86. class GtkFetchProgressAdapter(FetchProgress):
  87.     # FIXME: we really should have some sort of "we are at step"
  88.     # xy in the gui
  89.     # FIXME2: we need to thing about mediaCheck here too
  90.     def __init__(self, parent):
  91.         FetchProgress.__init__(self)
  92.         # if this is set to false the download will cancel
  93.         self.status = parent.label_status
  94.         self.progress = parent.progressbar_cache
  95.         self.parent = parent
  96.         self.canceled = False
  97.         self.button_cancel = parent.button_fetch_cancel
  98.         self.button_cancel.connect('clicked', self.cancelClicked)
  99.     def cancelClicked(self, widget):
  100.         logging.debug("cancelClicked")
  101.         self.canceled = True
  102.     def mediaChange(self, medium, drive):
  103.         #print "mediaChange %s %s" % (medium, drive)
  104.         msg = _("Please insert '%s' into the drive '%s'") % (medium,drive)
  105.         dialog = gtk.MessageDialog(parent=self.parent.window_main,
  106.                                    flags=gtk.DIALOG_MODAL,
  107.                                    type=gtk.MESSAGE_QUESTION,
  108.                                    buttons=gtk.BUTTONS_OK_CANCEL)
  109.         dialog.set_markup(msg)
  110.         res = dialog.run()
  111.         dialog.destroy()
  112.         if res == gtk.RESPONSE_OK:
  113.             return True
  114.         return False
  115.     def start(self):
  116.         #logging.debug("start")
  117.         FetchProgress.start(self)
  118.         self.progress.set_fraction(0)
  119.         self.status.show()
  120.         self.button_cancel.show()
  121.     def stop(self):
  122.         #logging.debug("stop")
  123.         self.progress.set_text(" ")
  124.         self.status.set_text(_("Fetching is complete"))
  125.         self.button_cancel.hide()
  126.     def pulse(self):
  127.         # FIXME: move the status_str and progress_str into python-apt
  128.         # (python-apt need i18n first for this)
  129.         FetchProgress.pulse(self)
  130.         self.progress.set_fraction(self.percent/100.0)
  131.         currentItem = self.currentItems + 1
  132.         if currentItem > self.totalItems:
  133.             currentItem = self.totalItems
  134.  
  135.         if self.currentCPS > 0:
  136.             self.status.set_text(_("Fetching file %li of %li at %sB/s") % (currentItem, self.totalItems, apt_pkg.SizeToStr(self.currentCPS)))
  137.             self.progress.set_text(_("About %s remaining") % FuzzyTimeToStr(self.eta))
  138.         else:
  139.             self.status.set_text(_("Fetching file %li of %li") % (currentItem, self.totalItems))
  140.             self.progress.set_text("  ")
  141.  
  142.         while gtk.events_pending():
  143.             gtk.main_iteration()
  144.         return (not self.canceled)
  145.  
  146. class GtkInstallProgressAdapter(InstallProgress):
  147.     # timeout with no status change when the terminal is expanded
  148.     # automatically
  149.     TIMEOUT_TERMINAL_ACTIVITY = 240
  150.     
  151.     def __init__(self,parent):
  152.         InstallProgress.__init__(self)
  153.         self._cache = None
  154.         self.label_status = parent.label_status
  155.         self.progress = parent.progressbar_cache
  156.         self.expander = parent.expander_terminal
  157.         self.term = parent._term
  158.         self.parent = parent
  159.         # setup the child waiting
  160.         reaper = vte.reaper_get()
  161.         reaper.connect("child-exited", self.child_exited)
  162.         # some options for dpkg to make it die less easily
  163.         apt_pkg.Config.Set("DPkg::StopOnError","False")
  164.  
  165.     def startUpdate(self):
  166.         InstallProgress.startUpdate(self)
  167.         self.finished = False
  168.         # FIXME: add support for the timeout
  169.         # of the terminal (to display something useful then)
  170.         # -> longer term, move this code into python-apt 
  171.         self.label_status.set_text(_("Applying changes"))
  172.         self.progress.set_fraction(0.0)
  173.         self.progress.set_text(" ")
  174.         self.expander.set_sensitive(True)
  175.         self.term.show()
  176.         # if no libgnome2-perl is installed show the terminal
  177.         frontend= os.environ.get("DEBIAN_FRONTEND") or "gnome"
  178.         if frontend == "gnome" and self._cache:
  179.           if (not self._cache.has_key("libgnome2-perl") or 
  180.               not self._cache["libgnome2-perl"].isInstalled):
  181.             frontend = "dialog"
  182.             self.expander.set_expanded(True)
  183.         self.env = ["VTE_PTY_KEEP_FD=%s"% self.writefd,
  184.                     "APT_LISTCHANGES_FRONTEND=none"]
  185.         if not os.environ.has_key("DEBIAN_FRONTEND"):
  186.           self.env.append("DEBIAN_FRONTEND=%s" % frontend)
  187.         # do a bit of time-keeping
  188.         self.start_time = 0.0
  189.         self.time_ui = 0.0
  190.         self.last_activity = 0.0
  191.         
  192.     def error(self, pkg, errormsg):
  193.         InstallProgress.error(self, pkg, errormsg)
  194.         logging.error("got an error from dpkg for pkg: '%s': '%s'" % (pkg, errormsg))
  195.     # we do not report followup errors from earlier failures
  196.         if gettext.dgettext('dpkg', "dependency problems - leaving unconfigured") in errormsg:
  197.       return False
  198.  
  199.         #self.expander_terminal.set_expanded(True)
  200.         self.parent.dialog_error.set_transient_for(self.parent.window_main)
  201.         summary = _("Could not install '%s'") % pkg
  202.         msg = _("The upgrade will continue but the '%s' package may not "
  203.                 "be in a working state. Please consider submitting a "
  204.                 "bug report about it.") % pkg
  205.         markup="<big><b>%s</b></big>\n\n%s" % (summary, msg)
  206.         self.parent.dialog_error.realize()
  207.         self.parent.dialog_error.window.set_functions(gtk.gdk.FUNC_MOVE)
  208.         self.parent.label_error.set_markup(markup)
  209.         self.parent.textview_error.get_buffer().set_text(utf8(errormsg))
  210.         self.parent.scroll_error.show()
  211.         self.parent.dialog_error.run()
  212.         self.parent.dialog_error.hide()
  213.  
  214.     def conffile(self, current, new):
  215.         logging.debug("got a conffile-prompt from dpkg for file: '%s'" % current)
  216.         start = time.time()
  217.         #self.expander.set_expanded(True)
  218.         prim = _("Replace the customized configuration file\n'%s'?") % current
  219.         sec = _("You will lose any changes you have made to this "
  220.                 "configuration file if you choose to replace it with "
  221.                 "a newer version.")
  222.         markup = "<span weight=\"bold\" size=\"larger\">%s </span> \n\n%s" % (prim, sec)
  223.         self.parent.label_conffile.set_markup(markup)
  224.         self.parent.dialog_conffile.set_transient_for(self.parent.window_main)
  225.  
  226.         # now get the diff
  227.         if os.path.exists("/usr/bin/diff"):
  228.           cmd = ["/usr/bin/diff", "-u", current, new]
  229.           diff = utf8(subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0])
  230.           self.parent.textview_conffile.get_buffer().set_text(diff)
  231.         else:
  232.           self.parent.textview_conffile.get_buffer().set_text(_("The 'diff' command was not found"))
  233.         res = self.parent.dialog_conffile.run()
  234.         self.parent.dialog_conffile.hide()
  235.         self.time_ui += time.time() - start
  236.         # if replace, send this to the terminal
  237.         if res == gtk.RESPONSE_YES:
  238.           self.term.feed_child("y\n")
  239.         else:
  240.           self.term.feed_child("n\n")
  241.         
  242.     def fork(self):
  243.         pid = self.term.forkpty(envv=self.env)
  244.         if pid == 0:
  245.           # WORKAROUND for broken feisty vte where envv does not work)
  246.           for env in self.env:
  247.             (key, value) = env.split("=")
  248.             os.environ[key] = value
  249.           # HACK to work around bug in python/vte and unregister the logging
  250.           #      atexit func in the child
  251.           sys.exitfunc = lambda: True
  252.         return pid
  253.  
  254.     def statusChange(self, pkg, percent, status):
  255.         # start the timer when the first package changes its status
  256.         if self.start_time == 0.0:
  257.           #print "setting start time to %s" % self.start_time
  258.           self.start_time = time.time()
  259.         self.progress.set_fraction(float(percent)/100.0)
  260.         self.label_status.set_text(status.strip())
  261.         # start showing when we gathered some data
  262.         if percent > 1.0:
  263.           self.last_activity = time.time()
  264.           self.activity_timeout_reported = False
  265.           delta = self.last_activity - self.start_time
  266.           # time wasted in conffile questions (or other ui activity)
  267.           delta -= self.time_ui
  268.           time_per_percent = (float(delta)/percent)
  269.           eta = (100.0 - percent) * time_per_percent
  270.           # only show if we have some sensible data (60sec < eta < 2days)
  271.           if eta > 61.0 and eta < (60*60*24*2):
  272.             self.progress.set_text(_("About %s remaining") % FuzzyTimeToStr(eta))
  273.           else:
  274.             self.progress.set_text(" ")
  275.  
  276.     def child_exited(self, term, pid, status):
  277.         # we need to capture the full status here (not only the WEXITSTATUS)
  278.         self.apt_status = status
  279.         self.finished = True
  280.  
  281.     def waitChild(self):
  282.         while not self.finished:
  283.             self.updateInterface()
  284.         return self.apt_status
  285.  
  286.     def finishUpdate(self):
  287.         self.label_status.set_text("")
  288.     
  289.     def updateInterface(self):
  290.         try:
  291.           InstallProgress.updateInterface(self)
  292.         except ValueError, e:
  293.           logging.error("got ValueError from InstallProgress.updateInterface. Line was '%s' (%s)" % (self.read, e))
  294.           # reset self.read so that it can continue reading and does not loop
  295.       self.read = ""
  296.         # check if we haven't started yet with packages, pulse then
  297.         if self.start_time == 0.0:
  298.           self.progress.pulse()
  299.           time.sleep(0.2)
  300.         # check about terminal activity
  301.         if self.last_activity > 0 and \
  302.            (self.last_activity + self.TIMEOUT_TERMINAL_ACTIVITY) < time.time():
  303.           if not self.activity_timeout_reported:
  304.             logging.warning("no activity on terminal for %s seconds (%s)" % (self.TIMEOUT_TERMINAL_ACTIVITY, self.label_status.get_text()))
  305.             self.activity_timeout_reported = True
  306.           self.parent.expander_terminal.set_expanded(True)
  307.         while gtk.events_pending():
  308.             gtk.main_iteration()
  309.     time.sleep(0.005)
  310.  
  311. class DistUpgradeVteTerminal(object):
  312.   def __init__(self, parent, term):
  313.     self.term = term
  314.     self.parent = parent
  315.   def call(self, cmd, hidden=False):
  316.     def wait_for_child(widget):
  317.       #print "wait for child finished"
  318.       self.finished=True
  319.     self.term.show()
  320.     self.term.connect("child-exited", wait_for_child)
  321.     self.parent.expander_terminal.set_sensitive(True)
  322.     if hidden==False:
  323.       self.parent.expander_terminal.set_expanded(True)
  324.     self.finished = False
  325.     pid = self.term.fork_command(command=cmd[0],argv=cmd)
  326.     if pid < 0:
  327.       # error
  328.       return 
  329.     while not self.finished:
  330.       while gtk.events_pending():
  331.         gtk.main_iteration()
  332.       time.sleep(0.1)
  333.     del self.finished
  334.  
  335. class DistUpgradeViewGtk(DistUpgradeView,SimpleGtkbuilderApp):
  336.     " gtk frontend of the distUpgrade tool "
  337.     def __init__(self, datadir=None, logdir=None):
  338.         self.logdir = logdir
  339.         if not datadir:
  340.           localedir=os.path.join(os.getcwd(),"mo")
  341.           gladedir=os.getcwd()
  342.         else:
  343.           localedir="/usr/share/locale/"
  344.           gladedir=os.path.join(datadir, "glade")
  345.  
  346.     # check if we have a display etc
  347.     gtk.init_check()
  348.  
  349.         try:
  350.           locale.bindtextdomain("update-manager",localedir)
  351.           gettext.textdomain("update-manager")
  352.         except Exception, e:
  353.           logging.warning("Error setting locales (%s)" % e)
  354.         
  355.         icons = gtk.icon_theme_get_default()
  356.         try:
  357.           gtk.window_set_default_icon(icons.load_icon("update-manager", 32, 0))
  358.         except gobject.GError, e:
  359.           logging.debug("error setting default icon, ignoring (%s)" % e)
  360.           pass
  361.         SimpleGtkbuilderApp.__init__(self, 
  362.                                      gladedir+"/DistUpgrade.ui", 
  363.                                      "update-manager")
  364.         # terminal stuff
  365.         self.create_terminal()
  366.  
  367.         self.prev_step = 0 # keep a record of the latest step
  368.         # we don't use this currently
  369.         #self.window_main.set_keep_above(True)
  370.         self.icontheme = gtk.icon_theme_get_default()
  371.         # we keep a reference pngloader around so that its in memory
  372.         # -> this avoid the issue that during the dapper->edgy upgrade
  373.         #    the loaders move from /usr/lib/gtk/2.4.0/loaders to 2.10.0
  374.         self.pngloader = gtk.gdk.PixbufLoader("png")
  375.         try:
  376.           self.svgloader = gtk.gdk.PixbufLoader("svg")
  377.           self.svgloader.close()
  378.         except gobject.GError, e:
  379.           logging.debug("svg pixbuf loader failed (%s)" % e)
  380.           pass
  381.         
  382.         self.window_main.realize()
  383.         self.window_main.window.set_functions(gtk.gdk.FUNC_MOVE)
  384.         self._opCacheProgress = GtkOpProgress(self.progressbar_cache)
  385.         self._fetchProgress = GtkFetchProgressAdapter(self)
  386.         self._cdromProgress = GtkCdromProgressAdapter(self)
  387.         self._installProgress = GtkInstallProgressAdapter(self)
  388.         # details dialog
  389.         self.details_list = gtk.ListStore(gobject.TYPE_STRING)
  390.         column = gtk.TreeViewColumn("")
  391.         render = gtk.CellRendererText()
  392.         column.pack_start(render, True)
  393.         column.add_attribute(render, "markup", 0)
  394.         self.treeview_details.append_column(column)
  395.         self.treeview_details.set_model(self.details_list)
  396.  
  397.         # Use italic style in the status labels
  398.         attrlist=pango.AttrList()
  399.         #attr = pango.AttrStyle(pango.STYLE_ITALIC, 0, -1)
  400.         attr = pango.AttrScale(pango.SCALE_SMALL, 0, -1)
  401.         attrlist.insert(attr)
  402.         self.label_status.set_property("attributes", attrlist)
  403.         # reasonable fault handler
  404.         sys.excepthook = self._handleException
  405.  
  406.     def _handleException(self, type, value, tb):
  407.       # we handle the exception here, hand it to apport and run the
  408.       # apport gui manually after it because we kill u-m during the upgrade
  409.       # to prevent it from poping up for reboot notifications or FF restart
  410.       # notifications or somesuch
  411.       import traceback
  412.       lines = traceback.format_exception(type, value, tb)
  413.       logging.error("not handled expection:\n%s" % "\n".join(lines))
  414.       # we can't be sure that apport will run in the middle of a upgrade
  415.       # so we still show a error message here
  416.       apport_crash(type, value, tb)
  417.       if not run_apport():
  418.         self.error(_("A fatal error occurred"),
  419.                    _("Please report this as a bug (if you haven't already) and include the "
  420.                      "files /var/log/dist-upgrade/main.log and "
  421.                      "/var/log/dist-upgrade/apt.log "
  422.                      "in your report. The upgrade is now aborted.\n"
  423.                      "Your original sources.list was saved in "
  424.                      "/etc/apt/sources.list.distUpgrade."),
  425.                    "\n".join(lines))
  426.       sys.exit(1)
  427.  
  428.     def getTerminal(self):
  429.         return DistUpgradeVteTerminal(self, self._term)
  430.  
  431.     def _key_press_handler(self, widget, keyev):
  432.       # user pressed ctrl-c
  433.       if len(keyev.string) == 1 and ord(keyev.string) == 3:
  434.         summary = _("Ctrl-c pressed")
  435.         msg = _("This will abort the operation and may leave the system "
  436.                 "in a broken state. Are you sure you want to do that?")
  437.         res = self.askYesNoQuestion(summary, msg)
  438.         logging.warning("ctrl-c press detected, user decided to pass it "
  439.                         "on: %s", res)        
  440.         return not res
  441.       return False
  442.  
  443.     def create_terminal(self):
  444.         " helper to create a vte terminal "
  445.         self._term = vte.Terminal()
  446.         self._term.connect("key-press-event", self._key_press_handler)
  447.         self._term.set_font_from_string("monospace 10")
  448.         self._term.connect("contents-changed", self._term_content_changed)
  449.         self._terminal_lines = []
  450.         self.hbox_custom.pack_start(self._term)
  451.         self._term.realize()
  452.         self.vscrollbar_terminal = gtk.VScrollbar()
  453.         self.vscrollbar_terminal.show()
  454.         self.hbox_custom.pack_start(self.vscrollbar_terminal)
  455.         self.vscrollbar_terminal.set_adjustment(self._term.get_adjustment())
  456.         try:
  457.           self._terminal_log = open(os.path.join(self.logdir,"term.log"),"w")
  458.         except Exception, e:
  459.           # if something goes wrong (permission denied etc), use stdout
  460.           self._terminal_log = sys.stdout
  461.         return self._term
  462.  
  463.     def _term_content_changed(self, term):
  464.         " called when the *visible* part of the terminal changes "
  465.         # get the current visible text, 
  466.         current_text = self._term.get_text(lambda a,b,c,d: True)
  467.         # see what we have currently and only print stuff that wasn't
  468.         # visible last time
  469.         new_lines = []
  470.         for line in current_text.split("\n"):
  471.           new_lines.append(line)
  472.           if not line in self._terminal_lines:
  473.             self._terminal_log.write(line+"\n")
  474.             try:
  475.               self._terminal_log.flush()
  476.             except IOError, e:
  477.               logging.exception("flush()")
  478.         self._terminal_lines = new_lines
  479.     def getFetchProgress(self):
  480.         return self._fetchProgress
  481.     def getInstallProgress(self, cache):
  482.         self._installProgress._cache = cache
  483.         return self._installProgress
  484.     def getOpCacheProgress(self):
  485.         return self._opCacheProgress
  486.     def getCdromProgress(self):
  487.         return self._cdromProgress
  488.     def updateStatus(self, msg):
  489.         self.label_status.set_text("%s" % msg)
  490.     def hideStep(self, step):
  491.         image = getattr(self,"image_step%i" % step)
  492.         label = getattr(self,"label_step%i" % step)
  493.         arrow = getattr(self,"arrow_step%i" % step)
  494.         image.hide()
  495.         label.hide()
  496.     def showStep(self, step):
  497.         image = getattr(self,"image_step%i" % step)
  498.         label = getattr(self,"label_step%i" % step)
  499.         image.show()
  500.         label.show()
  501.     def abort(self):
  502.         size = gtk.ICON_SIZE_MENU
  503.         step = self.prev_step
  504.         if step > 0:
  505.             image = getattr(self,"image_step%i" % step)
  506.             arrow = getattr(self,"arrow_step%i" % step)
  507.             image.set_from_stock(gtk.STOCK_CANCEL, size)
  508.             image.show()
  509.             arrow.hide()
  510.     def setStep(self, step):
  511.         if self.icontheme.rescan_if_needed():
  512.           logging.debug("icon theme changed, re-reading")
  513.         # first update the "previous" step as completed
  514.         size = gtk.ICON_SIZE_MENU
  515.         attrlist=pango.AttrList()
  516.         if self.prev_step:
  517.             image = getattr(self,"image_step%i" % self.prev_step)
  518.             label = getattr(self,"label_step%i" % self.prev_step)
  519.             arrow = getattr(self,"arrow_step%i" % self.prev_step)
  520.             label.set_property("attributes",attrlist)
  521.             image.set_from_stock(gtk.STOCK_APPLY, size)
  522.             image.show()
  523.             arrow.hide()
  524.         self.prev_step = step
  525.         # show the an arrow for the current step and make the label bold
  526.         image = getattr(self,"image_step%i" % step)
  527.         label = getattr(self,"label_step%i" % step)
  528.         arrow = getattr(self,"arrow_step%i" % step)
  529.         # check if that step was not hidden with hideStep()
  530.         if not label.get_property("visible"):
  531.           return
  532.         arrow.show()
  533.         image.hide()
  534.         attr = pango.AttrWeight(pango.WEIGHT_BOLD, 0, -1)
  535.         attrlist.insert(attr)
  536.         label.set_property("attributes",attrlist)
  537.  
  538.     def information(self, summary, msg, extended_msg=None):
  539.       self.dialog_information.set_transient_for(self.window_main)
  540.       msg = "<big><b>%s</b></big>\n\n%s" % (summary,msg)
  541.       self.label_information.set_markup(msg)
  542.       if extended_msg != None:
  543.         buffer = self.textview_information.get_buffer()
  544.         buffer.set_text(extended_msg)
  545.         self.scroll_information.show()
  546.       else:
  547.         self.scroll_information.hide()
  548.       self.dialog_information.realize()
  549.       self.dialog_information.window.set_functions(gtk.gdk.FUNC_MOVE)
  550.       self.dialog_information.run()
  551.       self.dialog_information.hide()
  552.       while gtk.events_pending():
  553.         gtk.main_iteration()
  554.  
  555.     def error(self, summary, msg, extended_msg=None):
  556.         self.dialog_error.set_transient_for(self.window_main)
  557.         #self.expander_terminal.set_expanded(True)
  558.         msg="<big><b>%s</b></big>\n\n%s" % (summary, msg)
  559.         self.label_error.set_markup(msg)
  560.         if extended_msg != None:
  561.             buffer = self.textview_error.get_buffer()
  562.             buffer.set_text(extended_msg)
  563.             self.scroll_error.show()
  564.         else:
  565.             self.scroll_error.hide()
  566.         self.dialog_error.realize()
  567.         self.dialog_error.window.set_functions(gtk.gdk.FUNC_MOVE)
  568.         self.dialog_error.run()
  569.         self.dialog_error.hide()
  570.         return False
  571.  
  572.     def confirmChanges(self, summary, changes, downloadSize, 
  573.                        actions=None, removal_bold=True):
  574.         # FIXME: add a whitelist here for packages that we expect to be
  575.         # removed (how to calc this automatically?)
  576.         if not DistUpgradeView.confirmChanges(self, summary, changes, downloadSize):
  577.           return False
  578.         # append warning
  579.         self.confirmChangesMessage +=  "\n\n<b>%s</b>" %  \
  580.             _("To prevent data loss close all open "
  581.               "applications and documents.")
  582.  
  583.         if actions != None:
  584.             self.button_cancel_changes.set_use_stock(False)
  585.             self.button_cancel_changes.set_use_underline(True)
  586.             self.button_cancel_changes.set_label(actions[0])
  587.             self.button_confirm_changes.set_label(actions[1])
  588.  
  589.         self.label_summary.set_markup("<big><b>%s</b></big>" % summary)
  590.         self.label_changes.set_markup(self.confirmChangesMessage)
  591.         # fill in the details
  592.         self.details_list.clear()
  593.         for dg in self.toDowngrade:
  594.             self.details_list.append([_("<b>Downgrade %s</b>") % dg])
  595.         for rm in self.toRemove:
  596.             s = _("Remove %s") % rm
  597.             if removal_bold:
  598.               s = "<b>%s</b>" % s
  599.             self.details_list.append([s])
  600.         for inst in self.toInstall:
  601.             self.details_list.append([_("Install %s") % inst])
  602.         for up in self.toUpgrade:
  603.             self.details_list.append([_("Upgrade %s") % up])
  604.         self.dialog_changes.set_transient_for(self.window_main)
  605.         # work around problem that scroll_to() does not 
  606.         # work when it is not realized
  607.         self.dialog_changes.realize()
  608.         self.treeview_details.realize()
  609.         self.treeview_details.set_cursor((0,))
  610.         self.treeview_details.scroll_to_point(0,0)
  611.         self.dialog_changes.window.set_functions(gtk.gdk.FUNC_MOVE)
  612.         res = self.dialog_changes.run()
  613.         self.dialog_changes.hide()
  614.         if res == gtk.RESPONSE_YES:
  615.             return True
  616.         return False
  617.  
  618.     def askYesNoQuestion(self, summary, msg, default='No'):
  619.         msg = "<big><b>%s</b></big>\n\n%s" % (summary,msg)
  620.         dialog = gtk.MessageDialog(parent=self.window_main,
  621.                                    flags=gtk.DIALOG_MODAL,
  622.                                    type=gtk.MESSAGE_QUESTION,
  623.                                    buttons=gtk.BUTTONS_YES_NO)
  624.         if default == 'No':
  625.           dialog.set_default_response(gtk.RESPONSE_NO)
  626.         else:
  627.           dialog.set_default_response(gtk.RESPONSE_YES)
  628.         dialog.set_markup(msg)
  629.         res = dialog.run()
  630.         dialog.destroy()
  631.         if res == gtk.RESPONSE_YES:
  632.             return True
  633.         return False
  634.     
  635.     def confirmRestart(self):
  636.         self.dialog_restart.set_transient_for(self.window_main)
  637.         self.dialog_restart.realize()
  638.         self.dialog_restart.window.set_functions(gtk.gdk.FUNC_MOVE)
  639.         res = self.dialog_restart.run()
  640.         self.dialog_restart.hide()
  641.         if res == gtk.RESPONSE_YES:
  642.             return True
  643.         return False
  644.  
  645.     def processEvents(self):
  646.         while gtk.events_pending():
  647.             gtk.main_iteration()
  648.  
  649.     def on_window_main_delete_event(self, widget, event):
  650.         self.dialog_cancel.set_transient_for(self.window_main)
  651.         self.dialog_cancel.realize()
  652.         self.dialog_cancel.window.set_functions(gtk.gdk.FUNC_MOVE)
  653.         res = self.dialog_cancel.run()
  654.         self.dialog_cancel.hide()
  655.         if res == gtk.RESPONSE_CANCEL:
  656.             sys.exit(1)
  657.         return True
  658.  
  659. if __name__ == "__main__":
  660.   
  661.   view = DistUpgradeViewGtk()
  662.   fp = GtkFetchProgressAdapter(view)
  663.   ip = GtkInstallProgressAdapter(view)
  664.  
  665.   cache = apt.Cache()
  666.   for pkg in sys.argv[1:]:
  667.     if cache[pkg].isInstalled:
  668.       cache[pkg].markDelete()
  669.     else:
  670.       cache[pkg].markInstall()
  671.   cache.commit(fp,ip)
  672.   gtk.main()
  673.   sys.exit(0)
  674.   
  675.   #sys.exit(0)
  676.   ip.conffile("TODO","TODO~")
  677.   view.getTerminal().call(["dpkg","--configure","-a"])
  678.   #view.getTerminal().call(["ls","-R","/usr"])
  679.   view.error("short","long",
  680.              "asfds afsdj af asdf asdf asf dsa fadsf asdf as fasf sextended\n"
  681.              "asfds afsdj af asdf asdf asf dsa fadsf asdf as fasf sextended\n"
  682.              "asfds afsdj af asdf asdf asf dsa fadsf asdf as fasf sextended\n"
  683.              "asfds afsdj af asdf asdf asf dsa fadsf asdf as fasf sextended\n"
  684.              "asfds afsdj af asdf asdf asf dsa fadsf asdf as fasf sextended\n"
  685.              "asfds afsdj af asdf asdf asf dsa fadsf asdf as fasf sextended\n"
  686.              "asfds afsdj af asdf asdf asf dsa fadsf asdf as fasf sextended\n"
  687.              )
  688.   view.confirmChanges("xx",[], 100)
  689.   
  690.